/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.commons.example;
import java.time.LocalDate;
import javafx.application.Application;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import javafx.util.Callback;
import org.joda.beans.Bean;
import org.joda.beans.MetaProperty;
import com.opengamma.basics.date.BusinessDayAdjustment;
import com.opengamma.basics.date.BusinessDayConvention;
import com.opengamma.basics.date.BusinessDayConventions;
import com.opengamma.basics.date.HolidayCalendar;
import com.opengamma.basics.date.HolidayCalendars;
import com.opengamma.basics.schedule.Frequency;
import com.opengamma.basics.schedule.PeriodicSchedule;
import com.opengamma.basics.schedule.RollConvention;
import com.opengamma.basics.schedule.RollConventions;
import com.opengamma.basics.schedule.Schedule;
import com.opengamma.basics.schedule.ScheduleException;
import com.opengamma.basics.schedule.SchedulePeriod;
import com.opengamma.basics.schedule.StubConvention;
/**
* A simple GUI demonstration of schedule generation.
* <p>
* This provides a GUI based on {@link PeriodicSchedule} and {@link Schedule}.
* <p>
* This GUI exists for demonstration purposes to aid with understanding schedule generation.
* It is not intended to be used in a production environment.
*/
public class ScheduleGui extends Application {
/**
* Launch GUI, no arguments needed.
*
* @param args no arguments needed
*/
public static void main(String[] args) {
launch(args);
}
//-------------------------------------------------------------------------
@Override
public void start(Stage primaryStage) {
// setup GUI elements
Label startLbl = new Label("Start date:");
DatePicker startInp = new DatePicker(LocalDate.now());
startLbl.setLabelFor(startInp);
startInp.setShowWeekNumbers(false);
Label endLbl = new Label("End date:");
DatePicker endInp = new DatePicker(LocalDate.now().plusYears(1));
endLbl.setLabelFor(endInp);
endInp.setShowWeekNumbers(false);
Label freqLbl = new Label("Frequency:");
ChoiceBox<Frequency> freqInp = new ChoiceBox<>(
FXCollections.observableArrayList(
Frequency.P1M, Frequency.P2M, Frequency.P3M, Frequency.P4M, Frequency.P6M, Frequency.P12M));
freqLbl.setLabelFor(freqInp);
freqInp.setValue(Frequency.P3M);
Label stubLbl = new Label("Stub:");
ObservableList<StubConvention> stubOptions = FXCollections.observableArrayList(StubConvention.values());
stubOptions.add(0, null);
ChoiceBox<StubConvention> stubInp = new ChoiceBox<>(stubOptions);
stubLbl.setLabelFor(stubInp);
stubInp.setValue(StubConvention.SHORT_INITIAL);
Label rollLbl = new Label("Roll:");
ChoiceBox<RollConvention> rollInp = new ChoiceBox<>(
FXCollections.observableArrayList(
null,
RollConventions.NONE,
RollConventions.EOM,
RollConventions.IMM,
RollConventions.IMMAUD,
RollConventions.IMMNZD,
RollConventions.SFE));
rollLbl.setLabelFor(rollInp);
rollInp.setValue(RollConventions.NONE);
Label bdcLbl = new Label("Adjust:");
ChoiceBox<BusinessDayConvention> bdcInp = new ChoiceBox<>(
FXCollections.observableArrayList(
BusinessDayConventions.NO_ADJUST,
BusinessDayConventions.FOLLOWING,
BusinessDayConventions.MODIFIED_FOLLOWING,
BusinessDayConventions.PRECEDING,
BusinessDayConventions.MODIFIED_PRECEDING,
BusinessDayConventions.MODIFIED_FOLLOWING_BI_MONTHLY,
BusinessDayConventions.NEAREST));
bdcLbl.setLabelFor(bdcInp);
bdcInp.setValue(BusinessDayConventions.MODIFIED_FOLLOWING);
Label holidayLbl = new Label("Holidays:");
ChoiceBox<HolidayCalendar> holidayInp = new ChoiceBox<>(
FXCollections.observableArrayList(
HolidayCalendars.CHZU,
HolidayCalendars.GBLO,
HolidayCalendars.EUTA,
HolidayCalendars.FRPA,
HolidayCalendars.USGS));
holidayLbl.setLabelFor(holidayInp);
holidayInp.setValue(HolidayCalendars.GBLO);
TableView<SchedulePeriod> resultGrid = new TableView<>();
TableColumn<SchedulePeriod, LocalDate> unadjustedCol = new TableColumn<>("Unadjusted dates");
TableColumn<SchedulePeriod, LocalDate> adjustedCol = new TableColumn<>("Adjusted dates");
TableColumn<SchedulePeriod, LocalDate> resultUnadjStartCol = new TableColumn<>("Start");
resultUnadjStartCol.setCellValueFactory(new TableCallback<>(SchedulePeriod.meta().unadjustedStartDate()));
TableColumn<SchedulePeriod, LocalDate> resultUnadjEndCol = new TableColumn<>("End");
resultUnadjEndCol.setCellValueFactory(new TableCallback<>(SchedulePeriod.meta().unadjustedEndDate()));
TableColumn<SchedulePeriod, LocalDate> resultStartCol = new TableColumn<>("Start");
resultStartCol.setCellValueFactory(new TableCallback<>(SchedulePeriod.meta().startDate()));
TableColumn<SchedulePeriod, LocalDate> resultEndCol = new TableColumn<>("End");
resultEndCol.setCellValueFactory(new TableCallback<>(SchedulePeriod.meta().endDate()));
unadjustedCol.getColumns().add(resultUnadjStartCol);
unadjustedCol.getColumns().add(resultUnadjEndCol);
adjustedCol.getColumns().add(resultStartCol);
adjustedCol.getColumns().add(resultEndCol);
resultGrid.getColumns().add(unadjustedCol);
resultGrid.getColumns().add(adjustedCol);
resultGrid.setPlaceholder(new Label("Schedule not yet generated"));
unadjustedCol.prefWidthProperty().bind(resultGrid.widthProperty().divide(2));
adjustedCol.prefWidthProperty().bind(resultGrid.widthProperty().divide(2));
resultUnadjStartCol.prefWidthProperty().bind(unadjustedCol.widthProperty().divide(2));
resultUnadjEndCol.prefWidthProperty().bind(unadjustedCol.widthProperty().divide(2));
resultStartCol.prefWidthProperty().bind(adjustedCol.widthProperty().divide(2));
resultEndCol.prefWidthProperty().bind(adjustedCol.widthProperty().divide(2));
// setup generation button
// this uses the GUI thread which is not the best idea
Button btn = new Button();
btn.setText("Generate");
btn.setOnAction(event -> {
LocalDate start = startInp.getValue();
LocalDate end = endInp.getValue();
Frequency freq = freqInp.getValue();
StubConvention stub = stubInp.getValue();
RollConvention roll = rollInp.getValue();
HolidayCalendar holCal = holidayInp.getValue();
BusinessDayConvention bdc = bdcInp.getValue();
BusinessDayAdjustment bda = BusinessDayAdjustment.of(bdc, holCal);
PeriodicSchedule defn = PeriodicSchedule.builder()
.startDate(start)
.endDate(end)
.frequency(freq)
.businessDayAdjustment(bda)
.stubConvention(stub)
.rollConvention(roll)
.build();
try {
Schedule schedule = defn.createSchedule();
System.out.println(schedule);
resultGrid.setItems(FXCollections.observableArrayList(schedule.getPeriods()));
} catch (ScheduleException ex) {
resultGrid.setItems(FXCollections.emptyObservableList());
resultGrid.setPlaceholder(new Label(ex.getMessage()));
System.out.println(ex.getMessage());
}
});
// layout the components
GridPane gp = new GridPane();
gp.setHgap(10);
gp.setVgap(10);
gp.setPadding(new Insets(0, 10, 0, 10));
gp.add(startLbl, 1, 1);
gp.add(startInp, 2, 1);
gp.add(endLbl, 1, 2);
gp.add(endInp, 2, 2);
gp.add(freqLbl, 1, 3);
gp.add(freqInp, 2, 3);
gp.add(bdcLbl, 3, 1);
gp.add(bdcInp, 4, 1);
gp.add(holidayLbl, 3, 2);
gp.add(holidayInp, 4, 2);
gp.add(stubLbl, 3, 3);
gp.add(stubInp, 4, 3);
gp.add(rollLbl, 3, 4);
gp.add(rollInp, 4, 4);
gp.add(btn, 3, 5, 2, 1);
gp.add(resultGrid, 1, 7, 4, 1);
BorderPane bp = new BorderPane(gp);
Scene scene = new Scene(bp, 600, 600);
// launch
primaryStage.setTitle("Periodic schedule generator");
primaryStage.setScene(scene);
primaryStage.show();
}
//-------------------------------------------------------------------------
// link Joda-Bean meta property to JavaFX
static class TableCallback<S extends Bean, T> implements Callback<CellDataFeatures<S, T>, ObservableValue<T>> {
private final MetaProperty<T> property;
public TableCallback(MetaProperty<T> property) {
this.property = property;
}
@Override
public ObservableValue<T> call(CellDataFeatures<S, T> param) {
return getCellDataReflectively(param.getValue());
}
private ObservableValue<T> getCellDataReflectively(S rowData) {
if (property == null || rowData == null) {
return null;
}
T value = property.get(rowData);
if (value == null) {
return null;
}
return new ReadOnlyObjectWrapper<T>(value);
}
}
}